<?php
// +----------------------------------------------------------------------
// | A3Mall
// +----------------------------------------------------------------------
// | Copyright (c) 2020 http://www.a3-mall.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: xzncit <158373108@qq.com>
// +----------------------------------------------------------------------

namespace app\common\model\users;

use app\common\model\base\A3Mall;
use app\common\model\Calculation;
use app\common\model\coin\CoinRuleRunTrade;
use app\common\traits\recordAllRun;
use think\facade\Db;

/**
 * 盈利统计处理
 * Class ProfitStatistics
 * @package app\common\model\users
 */
class ProfitStatistics extends A3Mall{
    use recordAllRun;   //使用链表查询处理

    // 获取小数位
    const SCALE = 20;

    const TYPE_LIST = [
        'ALL'   => 1,   // 统计所有
        'YEAR'  => 2,   // 统计年
        'MONTH' => 3,   // 统计月份
        'DAY'   => 4,   // 统计日
    ];

    /**
     * 默认时区列表
     */
    const TIMEZONE_LIST = [
        'PLATFORM'  => 'Asia/Shanghai',   // 平台时区
        'DEFAULT'   => 'Asia/Shanghai',   // 用户默认时区
    ];


    protected $name = "profit_statistics";

    /** 获取关联所有数据的列表
     * @param array $whereTmp  条件
     * @param array $limit  查询数量
     * @param string $order 排序
     * @param array $fields 查询字段（暂缺）
     * @return array
     */
    public function recordAll($whereTmp = [],$limit = [],$orderTmp = [],$fieldsTmp= []) {

        return $this->recordAllRun([$whereTmp,$limit,$orderTmp,$fieldsTmp],[],[
        ]);
    }




    public function intoStatistics(array $tradeDetails,int $userId,int $time) {
        $details = Calculation::profit($tradeDetails,null,true);
        $details = array_merge($details,[
            'reduce_fees'   => Calculation::reduceFees($tradeDetails,$userId),
            'service_charge'    => $tradeDetails['service_charge'],
            'service_charge_deducted'    => $tradeDetails['service_charge_deducted'],
        ]);
        $statisticsAddFunc = function($statisticsDetails) use($details) {
            foreach(['cost','sell','reserved'] as $field) {
                $statisticsDetails[$field] = Calculation::decimal(bcadd(array_key_exists($field,$statisticsDetails)?$statisticsDetails[$field]:0,$details[$field],30),'LARGE_AMOUNT');
            }
            foreach(['field_fees','reduce_fees','profit','service_charge','service_charge_deducted'] as $field) {
                $statisticsDetails[$field] = Calculation::decimal(bcadd(array_key_exists($field,$statisticsDetails)?$statisticsDetails[$field]:0,$details[$field],30));
            }

            return $statisticsDetails;
        };
        $userList = [0,$userId];
        $statisticsFields = ['user_record','cost','sell','reserved','field_fees','reduce_fees','profit','service_charge','service_charge_deducted','version'];
        foreach($userList as $userId) {
            $timezone = self::getTimezone($userId);
            $dateList = explode(' ',Calculation::date(' Y Y-m Y-m-d T',$time,$timezone));
            $short = array_pop($dateList);
            foreach($dateList as $date) {
                if($date) {
                    $statisticsDetails = [
                        'user_record'   => implode('_',[$short,$date,$userId]),
                        'time_zone' => $short,
                    ];
                } else {
                    $statisticsDetails = [
                        'user_record'   => $userId,
                        'time_zone' => '',
                    ];
                }

                if($tmpDetails = $this->recordAll(['user_record'=>$statisticsDetails['user_record']],1,null,$statisticsFields)) {
                    // 插入数据
                    $statisticsDetails = $statisticsAddFunc($tmpDetails);
                    $version = $statisticsDetails['version'];
                    $statisticsDetails['version'] =  Db::raw('if(version>250,1,version+1)');
                    // 更新数据
                    if(!$this->where([
                        'user_record'   => $statisticsDetails['user_record'],
                        'version'   => $version,
                    ])->update($statisticsDetails)) {
                        throw new \Exception('update Statistics error,tradeId is [' . $tradeDetails['id'] . '],userId is [' . $userId . ']');
                    }
                } else {
                    // 插入数据
                    $statisticsDetails = array_merge($statisticsAddFunc($statisticsDetails),[
                        'user_id'   => $userId,
                        'date'      => $date,
                        'version'   => 1,
                    ]);
                    $typeStr = 'ALL';
                    switch (strlen($statisticsDetails['date'])) {
                        case 4:
                            $typeStr = 'YEAR';
                            break;
                        case 7:
                            $typeStr = 'MONTH';
                            break;
                        case 10:
                            $typeStr = 'DAY';
                            break;
                    }
                    $statisticsDetails['type'] = self::TYPE_LIST[$typeStr];
                    if(!$this->insertGetId($statisticsDetails)) {
                        throw new \Exception('insert Statistics error,tradeId is [' . $tradeDetails['id'] . '],userId is [' . $userId . ']');
                    }
                }
            }
        }

        // 修改成功，添加日志
        if(!(new CoinRuleRunTrade())->orderUpdate($tradeDetails['id'],[
            'statistics'    => CoinRuleRunTrade::JOIN_STATISTICS_LIST['JOIN'],
        ],$tradeDetails['version'])) {
            throw new \Exception('update coin_rule_run_trade error,tradeId is [' . $tradeDetails['id'] . ']');
        }

        return true;
    }


    /**
     * 日期输出类型
     * @param $date
     * @return int
     */
    static function dateToType($date) {
        $typeStr = 'ALL';
        switch (strlen($date)) {
            case 4:
                $typeStr = 'YEAR';
                break;
            case 7:
                $typeStr = 'MONTH';
                break;
            case 10:
                $typeStr = 'DAY';
                break;
        }
        return self::TYPE_LIST[$typeStr];
    }


    /**
     * 获取报表指定的时区
     * @param int|null $userId
     * @return string
     */
    static function getTimezone(int $userId = null,$isShort = false) {
        $timezone = is_null($userId) || $userId < 1?self::TIMEZONE_LIST['PLATFORM']:self::TIMEZONE_LIST['DEFAULT'];
        return $isShort?Calculation::getTimezone($timezone,'short'):$timezone;
    }


    /**
     * 使用 union 合并获取详情
     * @param array $dateList 需要获取的日期
     * @param null $userIds 用户ID
     * @param array|null $fields 字段内容
     * @param string|null $timeZone 时区
     * @return array 返回结果集
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function unionByDate(array $dateList,$userIds = null,array $fields = null,string $timeZone = null) {
        $fields = is_null($fields)?'*':$fields;

        $timeZone = is_null($timeZone)?date('T'):$timeZone;
        $userWhere = [];
        if(!is_null($userIds) && !is_array($userIds)) {
            $userIds = [$userIds];
        }
        if(is_array($userIds)) {
            $userWhere[] = count($userIds) == 1?[
                'user_id','=',$userIds[0]
            ]:[
                'user_id','in',$userIds
            ];
        }
        $sqlList = [];
        $firstDb = clone $this;
        $i = 0;
        foreach($dateList as $date) {
            ++$i;
            $date = trim($date);
            $where = $userWhere;
            $typeKey = '';
            switch(strlen($date)) {
                case 0:     // 历史数据
                    $typeKey = 'ALL';
                    break;
                case 4:     // 年
                    $typeKey = 'YEAR';
                    break;
                case 7:     // 月份数据
                    $typeKey = 'MONTH';
                    break;
                case 10:    // 日期数据
                    $typeKey = 'DAY';
                    break;
                default:
                    throw new \Exception('date error');
            }
            $where[] = ['type','=',self::TYPE_LIST[$typeKey]];
            $where[] = ['date','=',$date];
            if($date) {
                $where[] = ['time_zone','=',$timeZone];
            }
            if($i == 1) {
                $firstDb = $firstDb->where($where)->field($fields);
            } else {
                $sqlList[] = $this->where($where)->field($fields)->fetchSql()->select();
            }
        }
        if($sqlList) {  // 判断是否需要关联处理
            $firstDb->union($sqlList,true);
        }
        $list = $firstDb->select();

        if(!count($list)) {
            return [];
        }
        $result = [];
        foreach ($list as $value) {
            $result[] = $value->getData();
        }
        return $result;
    }

}
